from tkinter import *
import time
from ..utils.loggers import dev_logger, prod_logger
from .funcbase import *
import threading
from .funcbase import AlltestReturnType


class FunctestR7C6(FunctestTemplate):
    def initData(self):
        MsgId = 0x280
        self.idIntVar.set(MsgId)
        self.testDatas = [
            UnitTestDataStructure(
                "发动机工作",
                "0000000000840000",
                "0000000000ff0000",
            ),
        ]

    def sendControlMsg(self, key):
        # wrapper包装是给按钮的回调函数用
        def wrapper():
            # 临时创建一个包装函数worker,把循环发送的任务放进去,然后再把这个函数丢进线程池中持续执行.
            def worker():
                while True:
                    # 循环发送间隔0.5s
                    time.sleep(0.1)
                    self._sendControlMsg(key)

            self.MASTER.pool.submit(worker)

        return wrapper

    def _sendControlMsg(self, key):
        """
        执行具体单个测试的函数闭包
        """

        strData = self.testDatas[key].send
        data = strData
        # dev_logger.debug(data)

        # 发送信息
        # with self.MASTER.recvMsgDequeLock:
            # self.MASTER.recvMsgDeque.clear()
        res = self.MASTER.sendcan1_manual(self.idIntVar.get(), data_string=data)
        if res == "error":
            self.sendDataLabelDict[key].configure(text="发送NG", background="red")
            return "error"
        else:
            self.sendDataLabelDict[key].configure(text="发送OK", background="green")
            # 正确发送后, 从总线读取响应信息
            # 读取之前把信息栈清空,然后再经过一段时间判断,收到的信息里有没有预期的数据
            # recvResult = self.checkRecvMsg()
            recvResult = True
            if recvResult is True:
                self.recvDataLabelDict[key].configure(text="返回OK", background="green")
            else:
                self.recvDataLabelDict[key].configure(text="返回NG", background="red")


class FunctestR7C7(FunctestTemplate):
    def initData(self):
        MsgId = 0x570
        self.idIntVar.set(MsgId)

        self.testDatas = [
            UnitTestDataStructure(
                "整车上电",
                "1000000080000000",
                "f0000000ff000000",
            ),
        ]

    def sendControlMsg(self, key):
        # 保存传递进来的key参数, wrapper包装是给按钮的回调函数用

        def wrapper():
            # 临时创建一个包装函数worker,把循环发送的任务放进去,然后再把这个函数丢进线程池中持续执行.
            dev_logger.debug("wrapper running....")

            def worker():
                dev_logger.debug("send while outer running....")
                while True:
                    # dev_logger.debug("send while inner running....")
                    # 循环发送间隔0.5s
                    time.sleep(0.1)
                    self._sendControlMsg(key)

            self.MASTER.pool.submit(worker)

        return wrapper

    def _sendControlMsg(self, key):
        """
        执行具体单个测试的函数闭包
        """

        strData = self.testDatas[key].send
        data = strData
        # dev_logger.debug(data)

        # 发送信息
        # dev_logger.debug(self.MASTER.recvMsgDeque)
        # with self.MASTER.recvMsgDequeLock:
            # self.MASTER.recvMsgDeque.clear()
        # dev_logger.debug(self.MASTER.recvMsgDeque)
        res = self.MASTER.sendcan1_manual(self.idIntVar.get(), data_string=data)
        if res == "error":
            self.sendDataLabelDict[key].configure(text="发送NG", background="red")
            return "error"
        else:
            self.sendDataLabelDict[key].configure(text="发送OK", background="green")
            # 正确发送后, 从总线读取响应信息
            # 读取之前把信息栈清空,然后再经过一段时间判断,收到的信息里有没有预期的数据
            # recvResult = self.checkRecvMsg()
            recvResult = True
            if recvResult is True:
                self.recvDataLabelDict[key].configure(text="返回OK", background="green")
            else:
                self.recvDataLabelDict[key].configure(text="返回NG", background="red")


class FunctestUnitR1C0_R1C1(FunctestTemplate):

    # 避免同时测试的线程锁
    test_lock= threading.RLock()

    def allTest(self):
        """
        左前座椅(主驾驶)
        此处用多线程,避免一个报错,把其他的都给堵塞死了
        """

        dev_logger.debug("run callback allTest....")

        def _allTest():
            dev_logger.debug(f"run _allTest....{self.testDatas}")

            # sendControlMsg 接收测试信息索引号为参数
            res = collections.defaultdict(int)

            # 线程测试时，只能同时运行R1C0和R1C1中的一个。
            with self.test_lock:
                for key, _ in enumerate(self.testDatas):
                    td = self.sendControlMsg(key)()
                    # td 是一个异步线程池任务的future对象，td.result()就是其任务执行后反馈的结果
                    # 可能反馈的结果就是在闭包包裹的_sendMsg函数中return的内容,有两种情况，“数据校验正确”或“数据校验失败”
                    # res 是一个字典，key是td.sendControlMsg的返回值,value是计数值
                    tdRet = td.result()
                    # dev_logger.debug(str(tdRet))
                    res[tdRet] += 1
            # res是个字典，示例如下：{"数据校验正确":5, "数据校验错误":3}
            dev_logger.debug(res)
            resString = ''
            # 把测试结果用字典形式列出来
            resFlag = True
            for key,value in res.items():
                # res 是一个字典，key是td.sendControlMsg的返回值,value是计数值
                resString += f'{key}:{value}\n'
                # 只要有一个错误，结果就是错误的，需要确认
                if key != '数据校验正确':
                    resFlag = False
            # 去掉最后的一个空行
            resString = resString[:-1]
            self.alltestResMsg.configure(text=resString)
            foreground = 'green' if resFlag else 'red'
            self.alltestResMsg.configure(foreground=foreground)

            dev_logger.debug('alltest 运行结束....')
            return resFlag, resString

        # 把发送和接受的工作放到一个单独的线程里执行,避免堵塞主线程,每个的发送和接收仍然是同步的,避免self.ecan的使用冲突
        # td = threading.Thread(target=_allTest)
        # td.start()
        # 把结果返回出去，在外面就可以通过result()接收到，内部函数return的返回值
        return self.testSinglePoolUnit.submit(_allTest)


class FunctestUnitR1C2_R1C3(FunctestTemplate):

    # 避免同时测试的线程锁
    test_lock = threading.RLock()

    def allTest(self):
        """
        左前座椅(主驾驶)
        此处用多线程,避免一个报错,把其他的都给堵塞死了
        """

        dev_logger.debug("run callback allTest....")

        def _allTest():
            dev_logger.debug(f"run _allTest....{self.testDatas}")

            # sendControlMsg 接收测试信息索引号为参数
            res = collections.defaultdict(int)

            # 线程测试时，只能同时运行R1C0和R1C1中的一个。
            with self.test_lock:
                for key, _ in enumerate(self.testDatas):
                    td = self.sendControlMsg(key)()
                    # td 是一个异步线程池任务的future对象，td.result()就是其任务执行后反馈的结果
                    # 可能反馈的结果就是在闭包包裹的_sendMsg函数中return的内容,有两种情况，“数据校验正确”或“数据校验失败”
                    # res 是一个字典，key是td.sendControlMsg的返回值,value是计数值
                    tdRet = td.result()
                    dev_logger.debug(str(tdRet))
                    res[tdRet] += 1
            # res是个字典，示例如下：{"数据校验正确":5, "数据校验错误":3}
            dev_logger.debug(res)
            resString = ''
            # 把测试结果用字典形式列出来
            resFlag = True
            for key,value in res.items():
                # res 是一个字典，key是td.sendControlMsg的返回值,value是计数值
                resString += f'{key}:{value}\n'
                # 只要有一个错误，结果就是错误的，需要确认
                if key != '数据校验正确':
                    resFlag = False
            # 去掉最后的一个空行
            resString = resString[:-1]
            self.alltestResMsg.configure(text=resString)
            foreground = 'green' if resFlag else 'red'
            self.alltestResMsg.configure(foreground=foreground)

            dev_logger.debug('alltest 运行结束....')

            result = AlltestReturnType(resFlag, resString)
            return resFlag, resString, result

        # 把发送和接受的工作放到一个单独的线程里执行,避免堵塞主线程,每个的发送和接收仍然是同步的,避免self.ecan的使用冲突
        # td = threading.Thread(target=_allTest)
        # td.start()
        # 把结果返回出去，在外面就可以通过result()接收到，内部函数return的返回值
        return self.testSinglePoolUnit.submit(_allTest)
